#pragma once

#ifndef __LIT__ITERATOR__HH__
#define __LIT__ITERATOR__HH__

#include <stdexcept>
#include <vector>
#include "LitExceptions.h"

namespace Lit
{
	template<typename ContainerType>
	class LIT_API Vector;
	template<typename ContainerType>
	class LIT_API Iterator
	{
	public:
		typename typedef ContainerType				container_type;
		typename typedef ContainerType::value_type	value_type;
		typename typedef ContainerType::value_type	value_ptr;
		typename typedef ContainerType::iterator	type;
	protected:
		size_t m_id;
		type start;
		type end;
		type current;
	public:
		Iterator( ContainerType & container )
			: start( container.begin() ), end( container.end() ), current( container.begin() ), m_id(0)
		{}
		Iterator( Vector<value_type> & container )
			: start( container.d.begin() ), end( container.d.end() ), current( container.d.begin() ), m_id(0)
		{}
		Iterator( type start_, type curr_, type end_ )
			: start( start_ ), current(curr_), end(end_), m_id(0)
		{}
		Iterator( const Iterator<ContainerType>& rk )
		{
			m_id=rk.m_id;
			start=rk.start;
			current=rk.current;
			end=rk.end;
		}
		Iterator& operator=( const Iterator<ContainerType>& rk )
		{
			m_id=rk.m_id;
			start=rk.start;
			current=rk.current;
			end=rk.end;
			return *this;
		}
		~Iterator(){ current = end; }

		void setEnd(){ current = end; }
		void setBegin(){ current = start; }

		value_type& get(){ return (*current); }
		value_type& operator->(){ return (*current); }
		value_type& operator*(){ return (*current); }

		bool hasNext() const{ return (current!=end); }
		Iterator& advance(){ 
			if( current == end )
				throw std::range_error( "Cannot increment iterator, already at end" );
			current ++;
			m_id++;
			return*this;
		}
		
		Iterator& operator++(){
			advance();
			return *this;
		}
		Iterator operator++( int ){
			Iterator i(*this);
			advance();
			return i;
		}
		operator bool() const{ return (current != end); }
		operator type() const{ return current; }
		bool operator ==( const Iterator<ContainerType>& rk ) const{ return current == rk.current; }
		bool operator !=( const Iterator<ContainerType>& rk ) const{ return current != rk.current; }

		bool operator ==( const type& rk ) const{ return current == rk; }
		bool operator !=( const type& rk ) const{ return current != rk; }

		size_t id() const{ return m_id; }
	};
	template<typename ContainerType>
	class LIT_API ConstIterator
	{
	public:
		typename typedef ContainerType::const_iterator	type;
		typename typedef ContainerType::value_type		value_type;
		typename typedef ContainerType					container_type;
	protected:
		type start;
		type end;
		type current;
		size_t m_id;
	public:
		ConstIterator( type start_, type curr_, type end_ )
			: start( start_ ), current(curr_), end(end_), m_id(0)
		{}
		ConstIterator( ContainerType & container )
			: start( container.begin() ), end( container.end() ), current( container.begin() ), m_id(0)
		{}
		ConstIterator( const Vector<value_type> & container )
			: start( container.d.begin() ), end( container.d.end() ), current( container.d.begin() ), m_id(0)
		{}
		ConstIterator( const ConstIterator<ContainerType>& rk )
		{
			start=rk.start;
			current=rk.current;
			end=rk.end;
			m_id=rk.m_id;
		}
		ConstIterator& operator=( const ConstIterator<ContainerType>& rk )
		{
			m_id = rk.m_id;
			start=rk.start;
			current=rk.current;
			end=rk.end;
			return *this;
		}
		~ConstIterator(){ current = end; }

		const value_type& get() const{ return (*current); }
		const value_type& operator->() const{ return (*current); }
		const value_type& operator*() const{ return (*current); }

		bool hasNext() const{ return (current!=end); }
		
		ConstIterator& advance(){ 
			if( current == end )
				throw std::range_error( "Cannot increment iterator, already at end" );
			current ++;
			m_id++;
			return*this;
		}
		
		ConstIterator& operator++(){
			advance();
			return *this;
		}
		ConstIterator operator++( int ){
			ConstIterator i(*this);
			advance();
			return i;
		}
		operator bool() const{ return (current != end); }
		operator type() const{ return current; }
		bool operator ==( const ConstIterator<ContainerType>& rk ) const{ return current == rk.current; }
		bool operator !=( const ConstIterator<ContainerType>& rk ) const{ return current != rk.current; }

		bool operator ==( const type& rk ) const{ return current == rk; }
		bool operator !=( const type& rk ) const{ return current != rk; }

		size_t id() const{ return m_id; }
	};
};
#endif